/**
 * 
 */
package cz.cuni.mff.abacs.burglar.logics.objects.positions;

import cz.cuni.mff.abacs.burglar.logics.DataMap;
import cz.cuni.mff.abacs.burglar.logics.objects.BaseInterface;
import cz.cuni.mff.abacs.burglar.logics.objects.BaseObject;
import cz.cuni.mff.abacs.burglar.logics.objects.Room;
import cz.cuni.mff.abacs.burglar.logics.objects.items.Inventory;
import cz.cuni.mff.abacs.burglar.logics.objects.items.InventoryImpl;
import cz.cuni.mff.abacs.burglar.logics.objects.items.Item;
import java.util.List;


/**
 * Holder of items.
 * 
 * @author abacs
 *
 */
public class Container extends BasePosition 
		implements Inventory, Position, Lockable {
	
	
	/** 
	 * Inventory implementation.
	 * 
	 * Changeable property. */
	protected final InventoryImpl _inventory = 
		new InventoryImpl();
	
	/**
	 * It can be locked.
	 * 
	 * Changeable property. 
	 * Default value is false. */
	protected boolean _isLocked = false;
	
	/**
	 * it can be opened or closed.
	 * 
	 * Changeable property. */
	protected boolean _isClosed = false;
	
	/**
	 * 
	 * not used property.
	 * 
	 * Changeable property. */
	protected boolean _isRigged = true;
	
	/** 
	 * The required key id to open it.
	 * 
	 * Not changeable property. 
	 * Default value is 0. */
	protected final int _keyId;
	
	
	// -------------------------------------------------------------------------
	// constructors:
	
	
	/**
	 * 
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param room
	 * @param isClosed
	 * @param referenceMap
	 */
	public Container(
			int id,
			int x,
			int y,
			Room room,
			boolean isClosed,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.CONTAINER, x, y, false, room, referenceMap);
		
		this._isClosed = isClosed;
		this._isLocked = false;
		this._keyId = -1;
	}
	
	
	/**
	 * 
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param roomId
	 * @param isClosed
	 * @param referenceMap
	 */
	public Container(
			int id,
			int x,
			int y,
			int roomId,
			boolean isClosed,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.CONTAINER, x, y, false, roomId, referenceMap);
		
		this._isClosed = isClosed;
		this._isLocked = false;
		this._keyId = 0;
		
	}
	
	
	/**
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param room
	 * @param isClosed
	 * @param isLocked
	 * @param keyId
	 * @param referenceMap
	 */
	public Container(
			int id,
			int x,
			int y,
			Room room,
			boolean isClosed,
			boolean isLocked,
			int keyId,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.CONTAINER, x, y, false, room, referenceMap);
		this._isClosed = isClosed;
		this._isLocked = isLocked;
		this._keyId = keyId;
		
	}
	
	
	/**
	 * 
	 * @param id
	 * @param x
	 * @param y
	 * @param room
	 * @param isClosed
	 * @param isLocked
	 * @param keyId
	 * @param referenceMap
	 */
	public Container(
			int id,
			int x,
			int y,
			int roomId,
			boolean isClosed,
			boolean isLocked,
			int keyId,
			DataMap referenceMap
	) {
		super(id, BaseObject.Type.CONTAINER, x, y, false, roomId, referenceMap);
		this._isClosed = isClosed;
		this._isLocked = isLocked;
		this._keyId = keyId;
		
	}
	
	
	/**
	 * Also takes the content of the container.
	 * 
	 * @param other
	 * @param referenceMap
	 */
	protected Container(Container other, DataMap referenceMap) {
		super(other, referenceMap);
		this._isClosed = other._isClosed;
		this._isLocked = other._isLocked;
		this._keyId = other._keyId;
		
		// items are not copied. they are static objects
		this._inventory.copyChangeables(other._inventory);
	}
	
	
	// -------------------------------------------------------------------------
	// Inventory:
	
	
	@Override
	public void addItem(Item item) {
		this._inventory.addItem(item);
	}
	
	
	@Override
	public void addItems(List<Item> items) {
		this._inventory.addItems(items);
	}
	
	
	@Override
	public Item removeItem(int id) {
		return this._inventory.removeItem(id);
	}
	
	
	@Override
	public boolean hasItem(int id) {
		return this._inventory.hasItem(id);
	}
	
	
	@Override
	public boolean hasItemOfType(BaseInterface.Type type) {
		return this._inventory.hasItemOfType(type);
	}
	
	
	@Override
	public int getItemIdOfType(Type type) {
		return this._inventory.getItemIdOfType(type);
	}
	
	
	@Override
	public List<Item> getItems() {
		return this._inventory.getItems();
	}
	
	
	// -------------------------------------------------------------------------
	// Lockable:
	
	
	@Override
	public boolean open() {
		if(this._isLocked == false || this._isClosed == false){
			this._isClosed = false;
			return true;
		}
		return false;
	}
	
	
	@Override
	public boolean close() {
		this._isClosed = true;
		return true;
	}

	
	@Override
	public boolean unlock(int key_id) {
		if(this._isLocked == false)
			return true;
		if(this._keyId == key_id){
			this._isLocked = false;
			return true;
		}
		return false;
	}
	
	
	@Override
	public boolean lock(int key_id) {
		if(this._isClosed == false)
			return false;
		if(this._isLocked)
			return true;
		if(this._keyId == key_id){
			this._isLocked = true;
			return true;
		}
		return false;
	}
	
	
	@Override
	public int getKeyId() {
		return this._keyId;
	}
	
	
	@Override
	public boolean isClosed() {
		return this._isClosed;
	}

	
	@Override
	public boolean isLocked() {
		return this._isLocked;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	@Override
	public boolean isOperable() {
		return true;
	}
	
	
	@Override
	public boolean isTrap() {
		return false;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * From far the agent can see whether the container is opened.
	 * It can see it's contents.
	 * It can't see whether it's locked.
	 */
	@Override
	public Position examinedFromFar() {
		Container newContainer = 
			new Container(
				this.getId(),
				this.getX(),
				this.getY(),
				this._roomId,
				this._isClosed,
				null
			);
		newContainer._inventory.copyChangeables(_inventory);
		return newContainer;
	}
	
	
	/**
	 * From near the agent can see whether the container is opened.
	 * It can see it's contents.
	 * It can see whether it's locked.
	 */
	@Override
	public Position examinedFromNear() {
		Container container = 
				new Container(
						this.getId(),
						this.getX(),
						this.getY(),
						this._roomId,
						this._isClosed,
						this._isLocked,
						this._keyId,
						null
				);
		
		container._inventory.copyChangeables(_inventory);
		
		return container;
	}
	
	
	@Override
	public boolean matchesFromFar(Position position) {
		if(super.matches(position) == false)
			return false;
		
		Container container = (Container) position;
		if(this._isClosed != container._isClosed)
			return false;
		
		return true;
	}
	
	
	@Override
	public boolean matchesFromClose(Position position) {
		if(super.matches(position) == false)
			return false;
		
		Container container = (Container) position;
		if(
			this._isClosed != container._isClosed ||
			this._isLocked != container._isLocked ||
			this.getKeyId() != container.getKeyId()
		)
			return false;
		
		return this._inventory.matchesFromClose(container._inventory);
	}
	
	
	@Override
	public void copyChangeables(Position original) {
		assert(original.isTypeOf(BaseInterface.Type.CONTAINER));
		Container container =  (Container)original;
		
		this._isLocked = container._isLocked;
		
		this._isClosed = container._isClosed;
		
		this._isRigged = container._isRigged;
		
		this._inventory.copyChangeables(container._inventory);
	}
	
	
	@Override
	public Position copy(DataMap reference) {
		return new Container(this, reference);
	}
	
	
}
